package com.yfp.operation.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.hy.corecode.idgen.WFGIdGenerator;
import com.yfp.common.core.domain.R;
import com.yfp.common.core.utils.StringUtils;
import com.yfp.common.datascope.annotation.DataScope;
import com.yfp.common.security.utils.SecurityUtils;
import com.yfp.operation.domain.*;
import com.yfp.operation.domain.dto.*;
import com.yfp.operation.domain.vo.DeviceCurrentComboPlanRoadVO;
import com.yfp.operation.domain.vo.EnterpriseOrderDetailVO;
import com.yfp.operation.domain.vo.EnterpriseOrderVO;
import com.yfp.operation.enums.ComboPlanStatus;
import com.yfp.operation.mapper.*;
import com.yfp.operation.service.MachineService;
import com.yfp.operation.service.ThrowPlanService;
import com.yfp.operation.utils.DateUtils;
import com.yfp.operation.domain.*;
import com.yfp.operation.domain.dto.*;
import com.yfp.operation.mapper.*;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 *
 * @version 1.0
 * @date 2024-06-26 12:17
 */
@Service
@Slf4j
public class ThrowPlanServiceImpl implements ThrowPlanService {

    @Resource
    private PlacementPlanMapper placementPlanMapper;
    @Resource
    private WFGIdGenerator wfgIdGenerator;
    @Resource
    private ComboPlanMapper comboPlanMapper;
    @Resource
    private CPComboRoadMapper cpComboRoadMapper;
    @Resource
    private ComboPlanDeviceMapper comboPlanDeviceMapper;
    @Resource
    private DeviceCurrentComboPlanRoadMapper deviceCurrentComboPlanRoadMapper;
    @Resource
    private DeviceCurrentComboStockMapper deviceCurrentComboStockMapper;
    @Resource
    private MachineService machineService;


    /**
     * 获取计划组列表
     *
     * @param gainPlacementPlanDTO
     * @return
     */
    @Override
    @DataScope(deptAlias = "p")
    public R<List<PlacementPlan>> getAllPlan(GainPlacementPlanDTO gainPlacementPlanDTO) {
        List<PlacementPlan> list = placementPlanMapper.getPlacementPlan(gainPlacementPlanDTO);
        return R.ok(list);
    }

    /**
     * 新增计划组
     *
     * @param insertPlacementPlanDTO
     * @return
     */
    @Transactional
    @Override
    public R<Void> addPlan(InsertPlacementPlanDTO insertPlacementPlanDTO) {

        // 判断计划组名称是否存在
        String planName = insertPlacementPlanDTO.getPlanName();
        Long deptId = SecurityUtils.getLoginUser().getSysUser().getDeptId();
        LambdaQueryWrapper<PlacementPlan> queryWrapper = new LambdaQueryWrapper<PlacementPlan>()
                .eq(PlacementPlan::getPlanName, planName)
                .eq(PlacementPlan::getDeptId,deptId);
        List<PlacementPlan> placementPlans = placementPlanMapper.selectList(queryWrapper);
        if (!placementPlans.isEmpty()) {
            log.info("计划组名称重复");
            return R.fail("该计划组名称已存在");
        }

        // 生成计划组id
        insertPlacementPlanDTO.setPlanId(String.valueOf(wfgIdGenerator.next()));
        // 状态
        insertPlacementPlanDTO.setStatus(ComboPlanStatus.AwaitStart.getStatus());
        // 部门id
        insertPlacementPlanDTO.setDeptId(deptId);
        placementPlanMapper.add(insertPlacementPlanDTO);
        log.info("新增计划组成功");
        return R.ok();
    }


    /**
     * 修改计划组
     *
     * @param updatePlacementPlanDTO
     * @return
     */
    @Override
    @Transactional
    public R<Void> updatePlan(UpdatePlacementPlanDTO updatePlacementPlanDTO) {
        // 获取计划组id
        String planId = updatePlacementPlanDTO.getPlanId();
        if (StringUtils.isEmpty(planId)) {
            log.info("参数不完整，缺少计划组id");
            return R.fail();
        }
        // 校验计划组名称是否存在
        String planName = updatePlacementPlanDTO.getPlanName();
        PlacementPlan pp = placementPlanMapper.getByPlanIdAndName(planId, planName);

        if (pp != null) {
            log.info("计划组名称重复");
            return R.fail("该计划组名称已存在");
        }

        // 修改
        placementPlanMapper.updatePlan(updatePlacementPlanDTO);

        return R.ok();
    }

    /**
     * 删除计划组
     *
     * @param placementPlan
     * @return
     */
    @Override
    @Transactional
    public R<Void> deleteByPlanId(@RequestBody PlacementPlan placementPlan) {
        String planId = placementPlan.getPlanId();
        // 删除
        placementPlanMapper.deleteByPlanId(planId);
        comboPlanMapper.deleteByPlanId(planId);
        comboPlanDeviceMapper.deleteByPlanId(planId);
        log.info("删除计划组成功,planId，{}", planId);
        return R.ok();
    }

    /**
     * 获取投放餐品计划列表
     *
     * @param gainComboPlanDTO
     * @return
     */
    @Override
    public List<ComboPlan> getAllComboPlan(GainComboPlanDTO gainComboPlanDTO) {

        // 计划组id
        String planId = gainComboPlanDTO.getPlanId();
        if (planId.isEmpty()) {
            log.info("参数不完整，缺少计划组id");
            return null;
        }
        if (gainComboPlanDTO.getStart_time() != null) {
            gainComboPlanDTO.setStart_time(gainComboPlanDTO.getStart_time() / 1000);
        }
        if (gainComboPlanDTO.getEnd_time() != null) {
            gainComboPlanDTO.setEnd_time(gainComboPlanDTO.getEnd_time() / 1000);
        }
        // 查询
        List<ComboPlan> list = comboPlanMapper.getAllComboPlan(gainComboPlanDTO);
        return list;
    }

    /**
     * 新增套餐计划
     *
     * @param comboPlanDTO
     * @return
     */
    @Override
    @Transactional
    public R<Void> addComboPlan(ComboPlanDTO comboPlanDTO) {

        // 计划组id
        String planId = comboPlanDTO.getPlanId();
        if (planId.isEmpty()) {
            log.info("参数不完整，缺少计划组id");
            return R.fail();
        }

        // 校验套餐计划名称是否存在
        String cPlanName = comboPlanMapper.getComboPlanName(comboPlanDTO);
        if (cPlanName != null) {
            log.info("套餐计划名称重复");
            return R.fail("该套餐计划名称重复");
        }


        // 套餐计划id
        comboPlanDTO.setCPlanId(String.valueOf(wfgIdGenerator.next()));
        comboPlanDTO.setStatus(ComboPlanStatus.AwaitStart.getStatus());
        comboPlanMapper.addComboPlan(comboPlanDTO);

        List<CPComboRoadDTO> comboRoadList = comboPlanDTO.getComboRoad();
        if (!comboRoadList.isEmpty()) {
            for (CPComboRoadDTO cpComboRoad : comboRoadList) {
                cpComboRoad.setId(String.valueOf(wfgIdGenerator.next()));
                cpComboRoad.setCPlanId(comboPlanDTO.getCPlanId());
            }
            // 批量插入
            cpComboRoadMapper.addAll(comboRoadList);
        }
        List<MachineDO> machineIds = comboPlanDTO.getMachineList();
        if (!machineIds.isEmpty()) {
            List<ComboPlanDevice> planDevices = new ArrayList<>();
            for (MachineDO machineDO : machineIds) {
                ComboPlanDevice comboPlanDevice = new ComboPlanDevice();
                comboPlanDevice.setCPlanId(comboPlanDTO.getCPlanId());
                comboPlanDevice.setMachineId(machineDO.getMachineId());
                comboPlanDevice.setId(String.valueOf(wfgIdGenerator.next()));
                planDevices.add(comboPlanDevice);
            }
            // 批量插入
            comboPlanDeviceMapper.addAll(planDevices);
        }
        log.info("新增套餐计划成功");
        return R.ok();
    }

    /**
     * 修改套餐计划
     *
     * @param comboPlanDTO
     * @return
     */
    @Override
    @Transactional
    public R<Void> updateComboPlan(ComboPlanDTO comboPlanDTO) {

        // 校验套餐计划名称是否存在
        String cPlanName = comboPlanDTO.getCPlanName();
        String name = comboPlanMapper.getComboPlanName(comboPlanDTO);
        if (name != null) {
            log.info("套餐计划名称重复");
            return R.fail("该套餐计划名称重复");
        }

        LambdaUpdateWrapper<ComboPlan> updateWrapper = new LambdaUpdateWrapper<ComboPlan>().set(ComboPlan::getCPlanName, cPlanName).eq(ComboPlan::getCPlanId, comboPlanDTO.getCPlanId());
        comboPlanMapper.update(null, updateWrapper);
        LambdaQueryWrapper<CPComboRoad> deleteWrapper = new LambdaQueryWrapper<CPComboRoad>()
                .eq(CPComboRoad::getCPlanId, comboPlanDTO.getCPlanId());
        // 删除时间相同、套餐计划id相同的数据
        cpComboRoadMapper.delete(deleteWrapper);
        if (!comboPlanDTO.getComboRoad().isEmpty()) {
            List<CPComboRoadDTO> comboRoadList = comboPlanDTO.getComboRoad();
//            List<Timestamp> collect = comboRoadList.stream().map(cpComboRoad -> cpComboRoad.getDate()).collect(Collectors.toList());
            for (CPComboRoadDTO cpComboRoad : comboRoadList) {
                cpComboRoad.setId(String.valueOf(wfgIdGenerator.next()));
                cpComboRoad.setCPlanId(comboPlanDTO.getCPlanId());
            }
            // 批量插入
            cpComboRoadMapper.addAll(comboRoadList);
        }
        log.info("修改套餐计划成功");
        return R.ok();
    }

    /**
     * 根据企业订单生成投放计划
     *
     * @param enterpriseOrderVO
     */
    @Override
    @Transactional
    public void autoEnterprisePlacementPlan(EnterpriseOrderVO enterpriseOrderVO) {
        Timestamp currentTime = DateUtils.addDay(new Timestamp(System.currentTimeMillis()), 1);
        List<DeviceCurrentComboPlanRoadVO> deviceCurrentComboPlanRoadVOS = comboPlanDeviceMapper.getByMachineIdAndStartDateAndEndDate(enterpriseOrderVO.getMachineId(), currentTime);
        if (!deviceCurrentComboPlanRoadVOS.isEmpty()) {
            for (DeviceCurrentComboPlanRoadVO deviceCurrentComboPlanRoadVO : deviceCurrentComboPlanRoadVOS) {
                comboPlanDeviceMapper.deleteByCPlanId(deviceCurrentComboPlanRoadVO.getCPlanId());
                comboPlanMapper.deleteByCPlanId(deviceCurrentComboPlanRoadVO.getCPlanId());
                cpComboRoadMapper.deleteByCPlanId(deviceCurrentComboPlanRoadVO.getCPlanId());
            }
        }
        MachineDO machine = machineService.getMachine(enterpriseOrderVO.getMachineId());
        ComboPlanDTO comboPlanDTO = new ComboPlanDTO();
        comboPlanDTO.setCPlanName(enterpriseOrderVO.getEnterpriseName() + DateUtils.addDay(1));
        comboPlanDTO.setPlanId("42585130332549");
        comboPlanDTO.setCPlanId(String.valueOf(wfgIdGenerator.next()));
        comboPlanDTO.setMachineType(machine.getMachineType() + "");
        Timestamp[] tomorrow = DateUtils.getTomorrow();
        comboPlanDTO.setStartTime(tomorrow[0]);
        comboPlanDTO.setEndTime(tomorrow[1]);
        comboPlanDTO.setStatus(ComboPlanStatus.Ongoing.getStatus());
        comboPlanMapper.addComboPlan(comboPlanDTO);

        List<ComboPlanDevice> planDevices = new ArrayList<>();
        ComboPlanDevice comboPlanDevice = new ComboPlanDevice();
        comboPlanDevice.setCPlanId(comboPlanDTO.getCPlanId());
        comboPlanDevice.setMachineId(enterpriseOrderVO.getMachineId());
        comboPlanDevice.setId(String.valueOf(wfgIdGenerator.next()));
        planDevices.add(comboPlanDevice);
        // 批量插入
        comboPlanDeviceMapper.addAll(planDevices);

        // 生成货道数据设备类型
        List<EnterpriseOrderDetailVO> enterpriseOrderDetails = enterpriseOrderVO.getEnterpriseOrderDetails();
        List<CPComboRoadDTO> comboRoadList = autoCPComboRoadDTO(machine.getMachineType(), comboPlanDTO.getCPlanId(), enterpriseOrderDetails);
        log.info("comboRoadList：{}", comboRoadList);
        if (!comboRoadList.isEmpty()) {
            // 批量插入
            cpComboRoadMapper.addAll(comboRoadList);
        }
        log.info("新增套餐计划成功");
    }

    /**
     * 删除企业投放计划
     *
     * @param machineId
     */
    @Override
    public void delEnterprisePlacementPlan(String machineId) {
        Timestamp currentTime = new Timestamp(System.currentTimeMillis());
        List<DeviceCurrentComboPlanRoadVO> deviceCurrentComboPlanRoadVOS = comboPlanDeviceMapper.getByMachineIdAndDate(machineId, currentTime);
        if (!deviceCurrentComboPlanRoadVOS.isEmpty()) {
            for (DeviceCurrentComboPlanRoadVO deviceCurrentComboPlanRoadVO : deviceCurrentComboPlanRoadVOS) {
                comboPlanDeviceMapper.deleteByCPlanId(deviceCurrentComboPlanRoadVO.getCPlanId());
                comboPlanMapper.deleteByCPlanId(deviceCurrentComboPlanRoadVO.getCPlanId());
                cpComboRoadMapper.deleteByCPlanId(deviceCurrentComboPlanRoadVO.getCPlanId());
            }
        }
    }


    /**
     * 根据企业订单生成投放计划
     *
     * @param machineType
     * @return
     */
    public List<CPComboRoadDTO> autoCPComboRoadDTO(int machineType,
                                                   String cPlanId,
                                                   List<EnterpriseOrderDetailVO> enterpriseOrderDetails) {
        // 行
        int hang = 0;
        // 列
        int lie = 0;
        // 容量
        int num = 0;
        switch (machineType) {
            case 2:
                // 二代机 行15 列4  *1
                hang = 15;
                lie = 4;
                num = 1;
                break;
            case 3:
                // 三代机 行8 列3   *3
                hang = 8;
                lie = 3;
                num = 3;
                break;
            case 4:
                // 四代机 行8 列4  *3
                hang = 8;
                lie = 4;
                num = 3;
                break;
        }

        // 总货道
        List<String> roadNumbers = new ArrayList<>();
        for (int i = 1; i <= hang; i++) {
            for (int j = 1; j <= lie; j++) {
                roadNumbers.add(i + "" + j);
            }
        }
        List<CPComboRoadDTO> comboRoadList = new ArrayList<>();
        Map<String, List<EnterpriseOrderDetailVO>> orderDetailVOMap = enterpriseOrderDetails.stream().collect(Collectors.groupingBy(EnterpriseOrderDetailVO::getComboId));

        CPComboRoadDTO cpComboRoadDTO = null;
        Timestamp[] tomorrow = DateUtils.getTomorrow();
        int totalWai = 0;
        for (String comboId : orderDetailVOMap.keySet()) {
            List<EnterpriseOrderDetailVO> enterpriseOrderDetailVOS = orderDetailVOMap.get(comboId);
            int comboCount = enterpriseOrderDetailVOS.stream().mapToInt(EnterpriseOrderDetailVO::getComboNum).sum();
            log.info("comboCount：{}", comboCount);
            // 计算占多少货道
            int wei = comboCount % num != 0 ? comboCount / num + 1 : comboCount / num;
            log.info("wei：{}", wei);
            for (int i = totalWai; i < roadNumbers.size(); i++) {
                if (i < wei + totalWai) {
                    cpComboRoadDTO = new CPComboRoadDTO();
                    cpComboRoadDTO.setComboId(comboId);
                    cpComboRoadDTO.setRoadNumber(roadNumbers.get(i));
                    cpComboRoadDTO.setComboNum(i + 1 == wei + totalWai && comboCount % num != 0 ? comboCount % num + "" : num + "");
                    cpComboRoadDTO.setDate(tomorrow[0]);
                    cpComboRoadDTO.setCPlanId(cPlanId);
                    cpComboRoadDTO.setId(String.valueOf(wfgIdGenerator.next()));
                    log.info("cpComboRoadDTO:{}", cpComboRoadDTO);
                    comboRoadList.add(cpComboRoadDTO);
                }
            }
            totalWai = totalWai + wei;
        }
        return comboRoadList;
    }

    /**
     * 修改状态
     *
     * @param cPlanId
     * @param status
     * @return
     */
    @Override
    @Transactional
    public R<Void> updateStatus(String cPlanId, String status) {

        // 获取套餐计划关联的设备id
        List<String> machineIds = comboPlanDeviceMapper.getMachineIds(cPlanId);

        // 如果要修改状态为进行中
        if (status.equals("Ongoing")) {
            // 校验该计划的设备是否有已经投放的计划
            Integer count = comboPlanMapper.getComboPlan(machineIds);
            if (count > 0) {
                log.info("该套餐计划关联的设备有已经投放的计划");
                return R.fail("该套餐计划关联的设备有已经投放的计划");
            }
            log.info("修改计划组状态为:{}", status);
            // 根据套餐计划id修改计划组状态
            placementPlanMapper.updateStatus(cPlanId, status);
        }
        // 修改
        comboPlanMapper.updateStatus(cPlanId, status);
        log.info("修改套餐计划状态成功");
        return R.ok();
    }

    /**
     * 根据餐品计划id获取设备信息
     *
     * @param cPlanId
     * @return
     */
    @Override
    public R<List<ComboPlanDevice>> getByMachineName(String cPlanId) {

        // 根据套餐计划id获取设备列表
        List<ComboPlanDevice> list = comboPlanDeviceMapper.getByCPlanId(cPlanId);

        return R.ok(list);
    }

    /**
     * 根据餐品计划id获取货道餐品信息
     */
    @Override
    public R<List<CPComboRoad>> getComboName(String cPlanId) {

        List<CPComboRoad> list = cpComboRoadMapper.getByCPlanId(cPlanId);
        return R.ok(list);
    }

    /**
     * 投放餐品计划选择商品下架
     *
     * @param comboSoldOutDTO
     * @return
     */
    @Override
    @Transactional
    public R<Void> comboSoldOut(ComboSoldOutDTO comboSoldOutDTO) {


        // 删除
        cpComboRoadMapper.deleteByCPlanIdAndComboId(comboSoldOutDTO);
        deviceCurrentComboPlanRoadMapper.deleteByCPlanIdAndComboId(comboSoldOutDTO);
        deviceCurrentComboStockMapper.deleteByCPlanIdAndComboId(comboSoldOutDTO);

        log.info("商品下架成功");
        return R.ok();
    }

    /**
     * 修改计划组状态
     *
     * @return
     */
    @Override
    @Transactional
    public R<Void> updatePlanStatus() {
        // 获取需要失效的计划组id
        List<String> planIds = placementPlanMapper.getplanId();
        if (CollUtil.isNotEmpty(planIds)) {
            comboPlanMapper.staleDated(planIds, ComboPlanStatus.End.getStatus());
        }
        placementPlanMapper.updatePlanStatus(ComboPlanStatus.End.getStatus());
        return R.ok();
    }

    /**
     * 定时修改套餐计划为结束状态
     *
     * @return
     */
    @Override
    public R<Void> updateComboPlanStatus() {
        comboPlanMapper.updateComboPlanStatus(ComboPlanStatus.End.getStatus());
        return R.ok();
    }
}
